package cn.itcast.bos.web.action.bc;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Controller;

import cn.itcast.bos.domain.bc.DecidedZone;
import cn.itcast.bos.domain.bc.Region;
import cn.itcast.bos.domain.bc.Subarea;
import cn.itcast.bos.utils.MyFileUtils;
import cn.itcast.bos.web.action.base.BaseAction;

@Controller("subAreaAction")
@Scope("prototype")
@Namespace("/bc")
@ParentPackage("bos")
public class SubAreaAction extends BaseAction<Subarea> {
	// 表示该方法执行 需要base 角色
	@Action(value = "subAreaAction_addSubarea", results = { @Result(name = "addSubarea", location = "/WEB-INF/pages/base/subarea.jsp") })
	public String addSubarea() {
		subAreaService.addSubarea(model);// 添加 model 没有id 如果修改 model 含有原始旧id
		return "addSubarea";
	}

	@Action(value = "subAreaAction_ajaxList")
	public String ajaxList() {
		// 查询所有分区
		List<Subarea> list = subAreaService.findAll();
		getValueStack().push(list);
		return SUCCESS;
	}

	// poi 下载
	@Action(value = "subAreaAction_download")
	public String download() throws Exception {
		// 1: 将表单添加 获取 条件查询 ... 通用代码抽取方法 shift+alt+t ---->extract method 选项
		List<Subarea> list = subAreaService.findAll(getSpecifecation());
		// 2: 将数据 封装 poi 对象 查询 poi 文档 如何使用浏览器下载... 一个流 两个头
		HSSFWorkbook workbook = new HSSFWorkbook();
		HSSFSheet sheet = workbook.createSheet();
		// 3: workbook 封装 数据 ... 表体
		// 分区编号 区域编码 关键字 起始号 结束号 单双号 位置信息
		HSSFRow firstRow = sheet.createRow(0);
		firstRow.createCell(0).setCellValue("分区编号");
		firstRow.createCell(1).setCellValue("区域编码");
		firstRow.createCell(2).setCellValue("关键字");
		firstRow.createCell(3).setCellValue("起始号");
		firstRow.createCell(4).setCellValue("结束号");
		firstRow.createCell(5).setCellValue("单双号");
		firstRow.createCell(6).setCellValue("位置信息");
		// 循环 数据
		for (Subarea s : list) {
			// 循环一次 创建一行...
			HSSFRow row = sheet.createRow(sheet.getLastRowNum() + 1);
			row.createCell(0).setCellValue(s.getId());
			row.createCell(1).setCellValue(s.getRegion().getId());
			row.createCell(2).setCellValue(s.getAddresskey());
			row.createCell(3).setCellValue(s.getStartnum());
			row.createCell(4).setCellValue(s.getEndnum());
			row.createCell(5).setCellValue(s.getSingle() + "");
			row.createCell(6).setCellValue(s.getPosition());
		}

		// 4: 浏览器下载 两个头
		String filename = "分区数据.xls";// 网络支持 mime 类型 text/html SevletContext
		HttpServletResponse response = getResponse();
		// 第一个头 文件类型获取
		ServletContext context = ServletActionContext.getServletContext();// 容器上下文对象
		String mimeType = context.getMimeType(filename);// 根据文件扩展名 自动获取对应MimeType
		response.setContentType(mimeType);// 下载第一个头完成
		// 第二个头 浏览器 附件下载 处理不同浏览器附件名中文乱码 狐火 base64 chrome ie 采用附件名乱码 url 解码 %%%%
		// Base64Encoder 自带jdk 没有该类 将工程环境切换成自己安装jdk jre 环境 filename 根据浏览器类型 做不同 编码处理之后字符串
		filename = MyFileUtils.encodeDownloadFilename(filename, getRequest().getHeader("user-agent"));
		response.setHeader("Content-Disposition", "attachment;filename=" + filename);// 服务器通知浏览器 以附件形式下载
		workbook.write(response.getOutputStream());// 浏览器下载
		// 类型 excel 附件名称
		return NONE;
	}

	// 多条件分页查询 有可能 没有条件参数查询 分页查询 也有可能含有1个或多个条件查询
	@Action(value = "subAreaAction_pageQuery")
	public String pageQuery() {
		// results 最终存放 total rows 服务器端不需要将请求参数回送给客户端
		Map<String, Object> results = new HashMap<String, Object>();
		// 1: Pageable 接口封装 datagrid 请求 page rows 当前页面和每页记录数
		Pageable pageRequest = new PageRequest(page - 1, rows);
		// 业务将调用spring-data接口实现 完成分页查询 获取分页数据返回值 Page对象
		// 2: 将model 参数信息 封装到 spring data 提供 Sepecification 类比 hibernate criteria QBC 查询 特点: 动态sql 优化编码
		// Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
		// Root 根 : 分页查询对应实体类 当前 Subarea
		// CriteriaQuery 简单语句查询和建立条件集合
		// CriteriaBuilder cb 复杂查询 建立条件 Restrictions
		// 思路 判断model条件 如果有条件 调用下列方法 如果没有条件 调用没有Specification
		// if (model.getRegion() == null && StringUtils.isBlank(model.getRegion().getProvince()) && StringUtils.isBlank(model.getRegion().getCity()) && StringUtils.isBlank(model.getRegion().getDistrict()) && StringUtils.isBlank(model.getAddresskey()) && model.getDecidedZone() == null) {
		Specification<Subarea> specification = getSpecifecation();
		Page<Subarea> pageData = subAreaService.findAll(pageRequest, specification); // model 分页条件参数---->Sepecification
		// Page [{},{},{}] List<T> 实现Itrerable 接口 json 序列化 数组 [{},{}]
		results.put("total", pageData.getTotalElements());// map 封装 easyui datagrid 插件需要数据格式 total 和 rows
		results.put("rows", pageData.getContent());
		getValueStack().push(results);
		return SUCCESS;
	}

	/**
	 * 封装 通用方法
	 * 
	 * @return
	 */
	private Specification<Subarea> getSpecifecation() {
		Specification<Subarea> specification = new Specification<Subarea>() {
			public Predicate toPredicate(Root<Subarea> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				// model 条件 封装 多表参数中 subarea region decidedzone mybatis
				// SetJoin<UserModel,DepModel> depJoin = root.join(root.getModel().getSet("setDep",DepModel.class) , JoinType.LEFT);
				List<Predicate> accordingList = new ArrayList<Predicate>();
				// 1: 连接region 区域信息 root--->Subarea regionJoin == region 表
				if (model.getRegion() != null) {
					// subarea 表 左外连接 region 表
					Join<Subarea, Region> regionJoin = root.join(root.getModel().getSingularAttribute("region", Region.class), JoinType.LEFT);
					if (StringUtils.isNotBlank(model.getRegion().getProvince())) {
						// 客户端 一定有省信息 p1 封装 省信息
						Predicate p1 = cb.like(regionJoin.get("province").as(String.class), "%" + model.getRegion().getProvince() + "%");
						accordingList.add(p1);
					}
					if (StringUtils.isNotBlank(model.getRegion().getCity())) {
						// 客户端 一定有省信息 p1 封装 省信息
						Predicate p2 = cb.like(regionJoin.get("city").as(String.class), "%" + model.getRegion().getCity() + "%");
						accordingList.add(p2);
					}
					if (StringUtils.isNotBlank(model.getRegion().getDistrict())) {
						// 客户端 一定有省信息 p1 封装 省信息
						Predicate p3 = cb.like(regionJoin.get("district").as(String.class), "%" + model.getRegion().getDistrict() + "%");
						accordingList.add(p3);
					}

				}
				// 2: 连接定区
				// 用户输入 定区编码id --->oid 查询信息
				if (model.getDecidedZone() != null && StringUtils.isNotBlank(model.getDecidedZone().getId())) {
					Predicate p4 = cb.equal(root.get("decidedZone").as(DecidedZone.class), model.getDecidedZone());
					accordingList.add(p4);
				}

				// 3: 自身关键字 模糊查询
				if (StringUtils.isNotBlank(model.getAddresskey())) {
					Predicate p5 = cb.like(root.get("addresskey").as(String.class), "%" + model.getAddresskey() + "%");
					accordingList.add(p5);
				}
				/**
				 * Predicate[] p = new Predicate[list.size()]; return cb.and(list.toArray(p));
				 */
				// 五个条件 and 创建一个数组 对象 Predicate new Predicate[0]作用 数组泛型类型
				Predicate[] predicates = accordingList.toArray(new Predicate[0]);
				return cb.and(predicates);// 5个条件 都是and
			}
		};
		return specification;
	}
}
